using AvaloniaMaidVSIX.Helpers;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.ComponentModel.Design;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Task = System.Threading.Tasks.Task;

namespace AvaloniaMaidVSIX.Commands
{
    /// <summary>
    /// Command handler
    /// </summary>
    internal sealed class SwitchViewModel2View
    {
        /// <summary>
        /// Command ID.
        /// </summary>
        public const int CommandId = 256;

        /// <summary>
        /// Command menu group (command set GUID).
        /// </summary>
        public static readonly Guid CommandSet = new Guid("c9f429f4-27e6-4573-8d08-bd5954b620f3");

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        /// <summary>
        /// Initializes a new instance of the <see cref="SwitchViewModel2View"/> class.
        /// Adds our command handlers for menu (commands must exist in the command table file)
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">Command service to add command to, not null.</param>
        private SwitchViewModel2View(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem = new MenuCommand(this.Execute, menuCommandID);
            commandService.AddCommand(menuItem);
        }

        /// <summary>
        /// Gets the instance of the command.
        /// </summary>
        public static SwitchViewModel2View Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the service provider from the owner package.
        /// </summary>
        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        /// <summary>
        /// Initializes the singleton instance of the command.
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package)
        {
            // Switch to the main thread - the call to AddCommand in SwitchViewModel2View's constructor requires
            // the UI thread.
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
            Instance = new SwitchViewModel2View(package, commandService);
        }

        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void Execute(object sender, EventArgs e)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            var dte = ServiceProvider.GetServiceAsync(typeof(DTE)).GetAwaiter().GetResult() as DTE2;

            var info = VSHelper.GetCurrentEditItemInfo(dte);

            if(info is null)
            {
        
                    // Show a message box to prove we were here
                    VsShellUtilities.ShowMessageBox(
                    this.package,
                        "遇到错误",
                        "文件上下文解析失败",
                        OLEMSGICON.OLEMSGICON_WARNING,
                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return;
            }

            var type =GetFileType(info.ItemFullPath);
            var convertedShortPath = GetConvertFilePath(type, info.ItemShortPath, info.ProjectDirPath);
            var convertedFullPath = Path.Combine(info.ProjectDirPath, convertedShortPath);

            if (File.Exists(convertedFullPath))
            {
                VsShellUtilities.OpenDocument(package, convertedFullPath);
            }
            else
            {
                // Show a message box to prove we were here
                VsShellUtilities.ShowMessageBox(
                this.package,
                    "遇到错误",
                    "无法找到文件去跳转",
                    OLEMSGICON.OLEMSGICON_WARNING,
                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
            }
              
        }

        #region impls

        static string[] _viewEndNameArray = new string[] { "View.xaml", "View.axaml", "UserControl.xaml", "UserControl.axaml", "Page.xaml", "Page.axaml", "Window.axaml","Window.xaml" };
        static string[] _viewCsEndNameArray = new string[] { "View.xaml.cs", "View.axaml.cs", "UserControl.xaml.cs", "UserControl.axaml.cs", "Page.xaml.cs", "Page.axaml.cs" };
        static string[] _viewNameArray = new string[] { "UserControl", "Page", "View", "Window" };
        static string[] _viewEndExtensionArray = new string[] { ".xaml", ".axaml" };

        public enum FileType
        {
            Unknown, View, ViewModel, ViewCS,
        }

        public static FileType GetFileType(string relPath)
        {
            if (_viewEndNameArray.Any(i => relPath.EndsWith(i, StringComparison.OrdinalIgnoreCase))) return FileType.View;
            if (_viewCsEndNameArray.Any(i => relPath.EndsWith(i, StringComparison.OrdinalIgnoreCase))) return FileType.ViewCS;
            if (relPath.EndsWith("ViewModel.cs", StringComparison.OrdinalIgnoreCase)) return FileType.ViewModel;

            return FileType.Unknown;
        }

        public static string GetConvertFilePath(FileType fileType, string relPath, string projectDir)
        {
            var result = string.Empty;
            switch (fileType)
            {
                case FileType.View:
                    result = relPath;
                    foreach (var item in _viewNameArray)
                    {
                        result = result.Replace(item, "ViewModel");
                    }
                    result = result.Replace(".xaml", ".cs").Replace(".axaml", ".cs");
                    break;
                case FileType.ViewModel:
                    result = relPath;

                    foreach (var viewName in _viewNameArray)
                    {
                        result = string.Empty;
                        foreach (var ext in _viewEndExtensionArray)
                        {
                            result = relPath.Replace("ViewModel", viewName).Replace(".cs", ext);
                            var fullPath = Path.Combine(projectDir, result);
                            if (File.Exists(fullPath)) break;

                            result = string.Empty;
                        }

                        if (string.IsNullOrWhiteSpace(result) == false) break;
                    }
                    break;
                case FileType.ViewCS:
                    result = relPath;
                    foreach (var item in _viewNameArray)
                    {
                        result = result.Replace(item, "ViewModel");
                    }
                    result = result.Replace(".xaml.cs", ".cs").Replace(".axaml.cs", ".cs");
                    break;
                default:
                    break;
            }

            return result;
        }

        #endregion
    }

}
